package pkg

import (
	"encoding/json"
	"myapp/config"
	"myapp/dal/model"
	"myapp/dal/query"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/spf13/cast"
	"gorm.io/gorm"

	uuid "github.com/gofrs/uuid"
)

// 客户端管理
type ClientManager struct {
	//客户端 map 储存并管理所有的长连接client，在线的为true，不在的为false
	clients map[string]map[*Client]bool
	//web端发送来的的message我们用broadcast来接收，并最后分发给所有的client
	broadcast chan []byte
	//新创建的长连接client
	register chan *Client
	//新注销的长连接client
	unregister chan *Client
}

// 客户端 Client
type Client struct {
	//用户id
	id string
	//连接的socket
	socket *websocket.Conn
	//发送的消息
	send chan []byte

	roomid  string
	user_id string
}

// 会把Message格式化成json
type Message struct {
	//消息struct
	Sender    string `json:"sender,omitempty"`    //发送者
	Recipient string `json:"recipient,omitempty"` //接收者
	//Content   string `json:"content,omitempty"`   //内容
	Contents []any  `json:"contents,omitempty"`
	Time     string `json:"time,omitempty"` //时间
	Roomid   string `json:"roomid,omitempty"`
}

type Content struct {
	Id      int       `json:"id,omitempty"`
	Type    string    `json:"type,omitempty"`
	RoomId  string    `json:"room_id,omitempty"`
	UserId  string    `json:"user_id,omitempty"`
	Name    string    `json:"name,omitempty"`
	Avatar  string    `json:"avatar,omitempty"`
	Content string    `json:"content,omitempty"`
	Time    time.Time `json:"time,omitempty"`
}

type ContentOutput struct {
	Id      int    `json:"id"`
	Type    string `json:"type"`
	RoomId  string `json:"room_id"`
	UserId  string `json:"user_id"`
	Name    string `json:"name"`
	Avatar  string `json:"avatar"`
	Content string `json:"content"`
	Time    string `json:"time"`
}

type User struct {
	Id           int
	Username     string
	Nickname     string
	Avatar       string
	BannedSwitch int
}

type Room struct {
	Id         int
	UserId     int
	Name       string
	Type       int
	Createtime int
}

type RoomUser struct {
	Id         int
	RoomId     string
	UserId     int
	Updatetime string
}

// 创建客户端管理者
var Manager = ClientManager{
	broadcast:  make(chan []byte),
	register:   make(chan *Client),
	unregister: make(chan *Client),
	clients:    make(map[string]map[*Client]bool),
}

func (manager *ClientManager) Start(db *gorm.DB) {
	query.SetDefault(db)
	for {
		select {
		//如果有新的连接接入,就通过channel把连接传递给conn
		case conn := <-manager.register:
			roomid := conn.roomid
			//把客户端的连接设置为true
			clients := manager.clients[roomid]
			if clients == nil {
				clients = make(map[*Client]bool)
				manager.clients[roomid] = clients
				//fmt.Println("在线人数:==",len(clients))
				//fmt.Println("rooms:==",manager.clients)
			}

			manager.clients[roomid][conn] = true
			//fmt.Println("在线人数:==",len(clients))
			//fmt.Println("rooms:==",manager.clients)

			//把返回连接成功的消息json格式化
			/*var contents []Content
			contents = append(contents, Content{Type: "connected", Content: "/A new socket has connected.", Time: time.Now().Format("2006-01-02 15:04:05")})

			jsonMessage, _ := json.Marshal(&Message{Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: roomid})
			//调用客户端的send方法，发送消息
			manager.send(jsonMessage, conn, roomid)*/

			if checkPerm(conn) {

				var musts []any
				var filters []any
				var sorts []any

				filters = append(filters, map[string]any{"term": map[string]any{
					"room_id": roomid,
				}})
				sorts = append(sorts, map[string]any{
					"time": map[string]any{
						"order": "desc",
					},
				})

				rs := EsManager{}.Search(config.Conf.EsChatMessageIndex, musts, filters, sorts, 0, 10)
				var posts []any
				for _, v := range rs.Hits.Hits {
					time, _ := FormatTime(ParseUTCToDatetime(v.Source["time"].(string)), false)
					v.Source["time"] = time
					posts = append(posts, v.Source)
				}

				jsonMessage, _ := json.Marshal(&Message{Contents: posts, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: roomid})
				manager.sendClient(jsonMessage, conn)

				query.ChatRoomUser.Where(query.ChatRoomUser.RoomID.Eq(cast.ToInt32(roomid)), query.ChatRoomUser.UserID.Eq(cast.ToInt32(conn.user_id))).UpdateColumns(model.ChatRoomUser{
					UpdatedAt: time.Now(),
				})
			}
			//如果连接断开了
		case conn := <-manager.unregister:
			roomid := conn.roomid
			//判断连接的状态，如果是true,就关闭send，删除连接client的值
			if _, ok := manager.clients[roomid][conn]; ok {
				close(conn.send)
				delete(manager.clients[roomid], conn)

				/*var contents []Content
				contents = append(contents, Content{Type: "disconnected", Content: "/A socket has disconnected.", Time: time.Now().Format("2006-01-02 15:04:05")})
				jsonMessage, _ := json.Marshal(&Message{Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: roomid})
				manager.send(jsonMessage, conn, roomid)*/

				query.ChatRoomUser.Where(query.ChatRoomUser.RoomID.Eq(cast.ToInt32(roomid)), query.ChatRoomUser.UserID.Eq(cast.ToInt32(conn.user_id))).UpdateColumns(model.ChatRoomUser{
					UpdatedAt: time.Now(),
				})
			}
			//广播
		case message := <-manager.broadcast:
			var data Message
			json.Unmarshal(message, &data)
			roomid := data.Roomid

			for conn := range manager.clients[roomid] {
				select {
				case conn.send <- message:
				default:
					close(conn.send)
					delete(manager.clients[roomid], conn)
				}
			}

			cont := data.Contents[0].(map[string]any)
			query.ChatRoom.Where(query.ChatRoom.ID.Eq(cast.ToInt32(roomid))).UpdateColumns(model.ChatRoom{
				UpdatedAt: time.Now(),
				Newmsg:    cont["content"].(string),
			})
		}
	}
}

// 定义客户端管理的send方法
func (manager *ClientManager) send(message []byte, ignore *Client, roomid string) {
	for conn := range manager.clients[roomid] {
		//不给屏蔽的连接发送消息
		if conn != ignore {
			conn.send <- message
		}
	}
}

func (manager *ClientManager) sendClient(message []byte, conn *Client) {
	conn.send <- message
}

// 定义客户端结构体的read方法
func (c *Client) read(db *gorm.DB) {
	defer func() {
		Manager.unregister <- c
		c.socket.Close()
	}()

	query.SetDefault(db)

	for {
		//读取消息
		_, message, err := c.socket.ReadMessage()
		//如果有错误信息，就注销这个连接然后关闭
		if err != nil {
			Manager.unregister <- c
			c.socket.Close()
			break
		}

		if !checkPerm(c) {
			Manager.unregister <- c
			c.socket.Close()
			break
		}

		user, _ := query.UserProfile.Where(query.UserProfile.UserID.Eq(cast.ToInt32(c.user_id))).Take()

		cont := Content{
			Type:    "say",
			Content: string(message),
			UserId:  c.user_id,
			Name:    user.Nickname,
			Avatar:  user.Avatar,
			Time:    time.Now(),
			RoomId:  c.roomid,
		}

		//如果没有错误信息就把信息放入broadcast
		var contents []any
		timeStr, _ := FormatTime(time.Now().Format("2006-01-02 15:04:05"), false)
		contOut := ContentOutput{
			Type:    cont.Type,
			Content: cont.Content,
			UserId:  cont.UserId,
			Name:    cont.Name,
			Avatar:  cont.Avatar,
			Time:    timeStr,
			RoomId:  cont.RoomId,
		}

		contents = append(contents, contOut)

		jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: c.roomid})
		Manager.broadcast <- jsonMessage

		//保存聊天记录，刷新时使用
		EsManager{}.Add(config.Conf.EsChatMessageIndex, time.Now().GoString(), cont)
	}
}

func (c *Client) write() {
	defer func() {
		c.socket.Close()
	}()

	for {
		select {
		//从send里读消息
		case message, ok := <-c.send:
			//如果没有消息
			if !ok {
				c.socket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			//有消息就写入，发送给web端
			c.socket.WriteMessage(websocket.TextMessage, message)
		}
	}
}

func WsHandler(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(c.Query("roomid")) == 0 {
			return
		}
		roomid := c.Query("roomid")

		userId, _ := c.Get("userID")
		user_id := 0
		if v, ok := userId.(uint); ok {
			user_id = int(v)
		}

		//将http协议升级成websocket协议
		conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
		if err != nil {
			http.NotFound(c.Writer, c.Request)
			return
		}

		//每一次连接都会新开一个client，client.id通过uuid生成保证每次都是不同的
		client := &Client{id: uuid.Must(uuid.NewV4()).String(), socket: conn, send: make(chan []byte), roomid: roomid, user_id: cast.ToString(user_id)}
		//注册一个新的链接
		Manager.register <- client

		//启动协程收web端传过来的消息
		go client.read(db)
		//启动协程把消息返回给web端
		go client.write()
	}
}
func checkPerm(conn *Client) bool {
	/*
		var user User
		where := "id = ?"
		if err = orm.Db.Table("trade_user").Select("id,username,nickname,avatar,banned_switch").Where(where, conn.user_id).Order("id desc").Limit(1).Find(&user).Error; err != nil {
			fmt.Println(err)
			return false
		}

		if user.BannedSwitch == 1 {
			var contents []Content
			contents = append(contents, Content{Type: "banned", Avatar: "https://ermaclub.cdbbox.com/uploads/20240511/09ab4a975e544f9ae55162fd439c9926.png", Content: "对不起，您已被禁言", Time: time.Now().Format("2006-01-02 15:04:05")})
			jsonMessage, _ := json.Marshal(&Message{Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: conn.roomid})
			Manager.sendClient(jsonMessage, conn)

			return false
		}

		var room Room
		where = "id = ?"
		if err = orm.Db.Table("trade_table").Select("*").Where(where, conn.roomid).Order("id desc").Limit(1).Find(&room).Error; err != nil {
			fmt.Println(err)

			var contents []Content
			contents = append(contents, Content{Type: "denied", Avatar: "https://ermaclub.cdbbox.com/uploads/20240511/09ab4a975e544f9ae55162fd439c9926.png", Content: "对不起，群组不存在", Time: time.Now().Format("2006-01-02 15:04:05")})
			jsonMessage, _ := json.Marshal(&Message{Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: conn.roomid})
			Manager.sendClient(jsonMessage, conn)

			return false
		}

		var roomUser RoomUser
		where = "table_id = ? and user_id = ?"
		if err = orm.Db.Table("trade_table_user").Select("*,table_id as room_id").Where(where, conn.roomid, conn.user_id).Order("id desc").Limit(1).Find(&roomUser).Error; err != nil {
			fmt.Println(err)

			var contents []Content
			contents = append(contents, Content{Type: "denied", Avatar: "https://ermaclub.cdbbox.com/uploads/20240511/09ab4a975e544f9ae55162fd439c9926.png", Content: "对不起，你没有该群权限", Time: time.Now().Format("2006-01-02 15:04:05")})
			jsonMessage, _ := json.Marshal(&Message{Contents: contents, Time: time.Now().Format("2006-01-02 15:04:05"), Roomid: conn.roomid})
			Manager.sendClient(jsonMessage, conn)

			return false
		}*/

	return true
}

func MessagesHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	if len(r.Form["roomid"]) == 0 {
		//model.JsonFail("缺少roomid", "", w, r)
	}
	//roomid := r.Form["roomid"][0]

	//var resp []Content
	// where := "room_id = ?"
	// if err = orm.Db.Table("trade_chat_message").Select("name,user_id,avatar, room_id,time,content").Where(where, roomid).Order("id desc").Limit(100).Find(&resp).Error; err != nil {
	// 	fmt.Println(err)
	// 	model.JsonFail("数据库出错", "", w, r)
	// }

	//model.JsonSuccess(resp, w, r)
}
